package com.cetc.cloud.kmga.util;

import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.*;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.httpclient.protocol.Protocol;

import java.io.*;
import java.util.Map;

/**
 * Created by wanli on 2016/4/12.
 */
public class HttpUtil {

    //常量
    public String APPLICATION_ATOM_XML = "application/atom+xml";
    public String APPLICATION_FORM_URLENCODED = "application/x-www-form-urlencoded";
    public String APPLICATION_JSON = "application/json";
    public String APPLICATION_OCTET_STREAM = "application/octet-stream";
    public String APPLICATION_SVG_XML = "application/svg+xml";
    public String APPLICATION_XHTML_XML = "application/xhtml+xml";
    public String APPLICATION_XML = "application/xml";
    public String MULTIPART_FORM_DATA = "multipart/form-data";
    public String TEXT_HTML = "text/html";
    public String TEXT_PLAIN = "text/plain";
    public String TEXT_XML = "text/xml";
    public String WILDCARD = "*/*";
    private String url = "";
    private String header;
    private String contentType;
//    private int contentLength;
    private byte[] response;
    private String responseString;
    private String fileName;

    private boolean httpsFlag = false;

    public HttpUtil(String url){
        this.url = url;
        if (url.contains("https")||url.contains("HTTPS")||url.contains("Https")){
            httpsFlag = true;
        }
    }

    public String getHeader() {
        return header;
    }

    private void setHeader(String header) {
        this.header = header;
    }

    public String getContentType() {
        return contentType;
    }

    private void setContentType(String contentType) {
        this.contentType = contentType;
    }

    public String getFileName() {
        return fileName;
    }

    private void setFileName(String fileName) {
        this.fileName = fileName;
    }

    //    public int getContentLength() {
//        return contentLength;
//    }
//
//    private void setContentLength(int contentLength) {
//        this.contentLength = contentLength;
//    }

    public byte[] getResponse() {
        return response;
    }

    private void setResponse(byte[] response) {
        this.response = response;
    }

    public String getResponseString() {
        return responseString;
    }

    private void setResponseString(String responseString) {
        this.responseString = responseString;
    }

    public Boolean sendGetRequest(){
        //LOGGER.info("request : start send informations...");
        //LOGGER.info("response : sent informations successfully.");
        return exeuteRequest(GetMethod());
    }

    public Boolean sendPostRequest(String message){
        //LOGGER.info("request : start send informations...");
        //LOGGER.info("response : sent informations successfully.");
        return exeuteRequest(PostMethod(message,null));
    }

    public Boolean sendPostRequest(String message,String contentType){
        //LOGGER.info("request : start send informations...");
        //LOGGER.info("response : sent informations successfully.");
        return exeuteRequest(PostMethod(message,contentType));
    }

    public Boolean sendPostRequest(Map<String,String> message,String contentType){
        //LOGGER.info("request : start send informations...");
        //LOGGER.info("response : sent informations successfully.");
        return exeuteRequest(PostMethod(message,contentType));
    }

    public Boolean sendPutRequest(String message){
        //LOGGER.info("request : start send informations...");
        //LOGGER.info("response : sent informations successfully.");
        return exeuteRequest(PutMethod(message,null));
    }

    public Boolean sendPutRequest(String message,String contentType){
        //LOGGER.info("request : start send informations...");
        //LOGGER.info("response : sent informations successfully.");
        return exeuteRequest(PutMethod(message,contentType));
    }

    public Boolean sendDeleteRequest(){
        //LOGGER.info("request : start send informations...");
        //LOGGER.info("response : sent informations successfully.");
        return exeuteRequest(DeleteMethod());
    }

    private GetMethod GetMethod(){
        GetMethod method = new GetMethod(this.url);
        method.setRequestHeader("Content-type", "text/xml; charset=utf-8");
        try
        {
            HttpMethodParams params = method.getParams();
            params.setContentCharset("UTF-8");
        } catch (Exception e) {
            //LOGGER.error("HTTP Exception occured while sending request.",e);
        }
        return method;
    }

    private PostMethod PostMethod(String message,String contentType){
        PostMethod method = new PostMethod(this.url);
        method.setRequestHeader("Content-type", contentType == null?TEXT_PLAIN:contentType+"; charset=utf-8");
        try {
            method.setRequestEntity(new StringRequestEntity(message,contentType == null?TEXT_PLAIN:contentType, "UTF-8"));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return method;
    }

    private PostMethod PostMethod(Map<String,String> messages,String contentType){
        PostMethod method = new PostMethod(this.url);
        method.setRequestHeader("Content-type", contentType == null?TEXT_PLAIN:contentType+"; charset=utf-8");
        try {

            NameValuePair[] params = new NameValuePair[messages.size()];
            int i = 0;
            for (Map.Entry<String,String> entry:messages.entrySet()){
                NameValuePair nameValuePair = new NameValuePair(entry.getKey(),entry.getValue());
                params[i] = nameValuePair;
                i++;
            }

            method.setRequestBody(params);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return method;
    }

    private PutMethod PutMethod(String message,String contentType){
        PutMethod method = new PutMethod(this.url);
        //method.setRequestHeader("Content-type", "text/xml; charset=utf-8");
        method.setRequestHeader("Content-type", contentType == null?TEXT_PLAIN:contentType+"; charset=utf-8");
        try {
            method.setRequestEntity(new StringRequestEntity(message,contentType == null?TEXT_PLAIN:contentType, "UTF-8"));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return method;
    }

    private DeleteMethod DeleteMethod(){
        DeleteMethod method = new DeleteMethod(this.url);
        method.setRequestHeader("Content-type", "text/xml; charset=utf-8");
        try
        {
            HttpMethodParams params = method.getParams();
            params.setContentCharset("UTF-8");
        } catch (Exception e) {
            //LOGGER.error("HTTP Exception occured while sending request.",e);
        }
        return method;
    }
    private boolean exeuteRequest(HttpMethod method){
        boolean response = false;
        try {
            HttpClient client = new HttpClient();

            if (httpsFlag){
                Protocol https = new Protocol("https", new HTTPSSecureProtocolSocketFactory(), 443);
                Protocol.registerProtocol("https", https);
            }

            client.setConnectionTimeout(10000);
            int status = client.executeMethod(method);

            this.analysisHeaders(method.getResponseHeaders());

            if (this.getContentType() == null){
                this.setResponseString(method.getResponseBodyAsString());
            }
            else{
                if(this.getContentType().contains("text") || this.getContentType().contains("json")){
                    this.inputStream2String(method.getResponseBodyAsStream());
                }
                else {
                    this.inputStream2Bytes(method.getResponseBodyAsStream());
                }
            }

            if (status == 200){
                response = true;
            }
            else{
                response = false;
            }
//            if (status != 200) {
//                if (status == 401) {
//                    if (client.executeMethod(method) == 401) {
//                        //throw new Exception(
//                        //        "Authorization failed. Please check the credentials.");
//                    }
//                } else {
//                    if (status == 400) {
//;
//                    }
//                }
//                return response;
//            }
            if (httpsFlag){
                Protocol.unregisterProtocol("https");
            }
        } catch (Exception e) {
            //LOGGER.error("HTTP Exception occured while sending request.",e);
            e.printStackTrace();
        } finally {
            method.releaseConnection();
        }
        return response;
    }

    //解析headers
    private void analysisHeaders(Header[] headers){

        for (Header h : headers ){
            if ("Content-Disposition".equals(h.getName())){
                this.setHeader(h.getValue());
                this.setFileName(h.getValue().split(";")[1].split("=")[1]);
            }
            if ("Content-Type".equals(h.getName())){
                this.setContentType(h.getValue());
            }
//            if ("Content-Length".equals(h.getName())){
//                this.setContentLength(Integer.parseInt(h.getValue()));
//            }
        }
    }

    //将InputStream转成byte[]
    private void inputStream2Bytes(InputStream inputStream){

        ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
        try {
            byte[] buff = new byte[100]; //buff用于存放循环读取的临时数据
            int rc = 0;
            while ((rc = inputStream.read(buff, 0, 100)) > 0) {
                swapStream.write(buff, 0, rc);
            }
            this.setResponse(swapStream.toByteArray());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //将InputStream转成String
    public void inputStream2String(InputStream inputStream) {
        try {
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));
        StringBuilder sb = new StringBuilder();

        String line = null;

            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
            this.setResponseString(sb.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //解析文件头
    private String bytesToHexString(byte[] src){
        StringBuilder builder = new StringBuilder();
        if (src == null || src.length <= 0){
            return null;
        }
        String hv;
        for (int i = 0; i < src.length; i++){
            hv = Integer.toHexString(src[i] & 0xFF).toUpperCase();
            if (hv.length() < 2){
                builder.append(0);
            }
            builder.append(hv);
        }
        System.out.println(builder.toString());
        return builder.toString();
    }

    //构造SOAP报文
    public String createSoapMessage(String methodName,String nameSpace,String params){
        StringBuffer sb = new StringBuffer("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
        sb.append("<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">");
        sb.append("<soap:Body>");
        //拼装方法名称
        sb.append("<"+methodName+" xmlns=\""+nameSpace+"\">");
        //拼装参数
        for (String str :params.split(";")) {
            String key = str.split("=")[0];
            String value = str.split("=")[1];
            sb.append("<"+key+" xmlns=\"\">"+value+"</"+key+">");
        }
        sb.append("</"+methodName+">");
        sb.append("</soap:Body>");
        sb.append("</soap:Envelope>");

        return sb.toString();
    }

    //解析SOAP报文(只针对JAX-WS)
    public String analysisSoapMessage(String responseString){
       return responseString.split("<return>")[1].split("</return>")[0];
    }

}
